package p.ithorns.integration.sharding;

import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.RangeShardingValue;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;

/**
 * RangeTableSharding
 * 表范围分片算法
 *
 * @author ithorns
 * @version 1.0
 * @date 2021/9/6 23:14
 */
public class RangeTableSharding implements RangeShardingAlgorithm<Long> {


    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames,
                                         RangeShardingValue<Long> rangeShardingValue) {

        final ArrayList<String> result = new ArrayList<>();
        final Range<Long> range = rangeShardingValue.getValueRange();
        long startMillisecond = range.lowerEndpoint();
        long endMillisecond = range.upperEndpoint();

        // 起始年和结束年
        LocalDateTime startDateTime = LocalDateUtil.asLocalDateTime(startMillisecond);
        LocalDateTime endDateTime = LocalDateUtil.asLocalDateTime(endMillisecond);
        int startYear = startDateTime.getYear();
        int endYear = endDateTime.getYear();
        // 起始月和结束月
        int startMonth = startDateTime.getMonthValue();
        int endMonth = endDateTime.getMonthValue();

        int startYearJoinMonth =  startYear * 100 + endMonth;
        int endYearJoinMonth = endYear * 100 + endMonth;
        return startYear == endYear
                ? theSameYear(startMonth, endMonth, availableTargetNames, result)
                : differentYear(startYear, endYear, startMonth, endMonth, startYearJoinMonth, endYearJoinMonth, availableTargetNames, result);
    }


    /**
     * 同年，但可能不同月
     */
    private Collection<String> theSameYear(int startMonth,
                                           int endMonth,
                                           Collection<String> availableTargetNames,
                                           ArrayList<String> result) {

        return startMonth == endMonth
                ? theSameMonth(startMonth, availableTargetNames, result)
                : differentMonth(startMonth, endMonth, availableTargetNames, result);
    }

    /**
     * 同年同月
     */
    private Collection<String> theSameMonth(int startMonth,
                                            Collection<String> availableTargetNames,
                                            ArrayList<String> result) {

        String startMonthStr = String.valueOf(startMonth);
        if (startMonthStr.length() == 1) {
            startMonthStr = "0" + startMonthStr;
        }
        for (String availableTargetName : availableTargetNames) {
            if (availableTargetName.endsWith(startMonthStr)) {
                result.add(availableTargetName);
            }
        }
        return result;
    }

    /**
     * 同年不同月
     */
    private Collection<String> differentMonth(int startMonth, int endMonth,
                                              Collection<String> availableTargetNames,
                                              ArrayList<String> result) {

        for (String availableTargetName : availableTargetNames) {
            for (int i = startMonth; i <= endMonth; i++) {
                String monthStr = String.valueOf(i);
                if (monthStr.length() == 1) {
                    monthStr = "0" + monthStr;
                }
                if (availableTargetName.endsWith(monthStr)) {
                    result.add(availableTargetName);
                }
            }
        }
        return result;
    }


    /**
     * 不同年，跨年，最少两个月，需要考虑跨两年以上的情况
     */
    private Collection<String> differentYear(int startYear, int endYear, int startMonth, int endMonth,
                                             int startYearJoinMonth, int endYearJoinMonth,
                                             Collection<String> availableTargetNames, ArrayList<String> result) {

        return endYear - startYear == 1
                ? twoYears(startYear, endYear, startMonth, endMonth, startYearJoinMonth, endYearJoinMonth, availableTargetNames, result)
                : moreThanTwoYears(startYear, endYear, startMonth, endMonth, availableTargetNames, result);
    }


    /**
     * 两年
     */
    private Collection<String> twoYears(int startYear, int endYear, int startMonth, int endMonth,
                                        int startYearJoinMonth, int endYearJoinMonth,
                                        Collection<String> availableTargetNames, ArrayList<String> result) {

        int endCondition;
        endCondition = Integer.parseInt(startYear + "12");
        for (int i = startYearJoinMonth; i <= endCondition; i++) {
            for (String availableTargetName : availableTargetNames) {
                // 如果多库此算法sharding会匹配两次，需要年份加月份来判断，只使用月份的话有问题
                if (availableTargetName.endsWith(String.valueOf(i))) {
                    result.add(availableTargetName);
                }
            }
        }

        endCondition = Integer.parseInt(endYear + "01");
        for (int i = endYearJoinMonth; i >= endCondition; i--) {
            for (String availableTargetName : availableTargetNames) {
                if (availableTargetName.endsWith(String.valueOf(i))) {
                    result.add(availableTargetName);
                }
            }
        }
        return result;
    }


    /**
     * 两年以上，如果数据量大的话不建议跨太多库
     */
    private Collection<String> moreThanTwoYears(int startYear, int endYear, int startMonth, int endMonth,
                                                Collection<String> availableTargetNames,
                                                ArrayList<String> result) {
        return null;
    }

}